/*
 *  xml_connection.cc
 *  Untitled
 *
 *  Created by Ben Nolan on 3/11/08.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#include "xml_connection.h"
#include "message.h"

#include <boost/bind.hpp>
#include <iomanip>

namespace ba = boost::asio;

namespace Wonderland{

void XmlConnection::onProtocolFailure(){
	std::cout << "Protocol failure. Disconnecting." << std::endl;
	socket_.close();
	onDisconnected();
}

void XmlConnection::acceptConnection(){
	std::cout << "Connection established..." << std::endl;
	
	prepareForMessage();
	
	onConnected();
}

void XmlConnection::prepareForMessage(){
	// Maximum messages size of 16k
	//body_.resize(16000);
	
	boost::asio::async_read_until(
		socket_, body_, '\n',
		boost::bind(
		  &XmlConnection::onMessageBody, this, boost::asio::placeholders::error
		)
	);
}
	
//void XmlConnection::onMessageHeader(const boost::system::error_code& error){
//	if (error){
//		onDisconnected();
//		return;
//	}
//
//	// Read the size of the body (hexadecimal)
//	unsigned int size;
//	std::istringstream iss(header_);
//	iss >> std::setbase(16) >> size;
//
//	// Check sizes
//	if((size>0xFFFF) || (iss.fail())){
//		onProtocolFailure();
//		return;
//	}
//
//	// Allocate space for the body and read it in
//	body_.resize(size);
//	boost::asio::async_read(socket_,
//		boost::asio::buffer(body_),
//		boost::bind(
//			&XmlConnection::onMessageBody, this, boost::asio::placeholders::error
//		)
//	);
//}

void XmlConnection::onMessageBody(const boost::system::error_code& error){
	if (error){
		onDisconnected();
		return;
	}
	
	// Hack the streambuf into a string
	std::istreambuf_iterator<char> iter(&body_);
	std::istreambuf_iterator<char> end;
	std::string messageBody(iter, end);

//	std::cout << "Message recieved.." << std::endl;
//	std::cout << "[" << messageBody << "]" << std::endl;

	// Process the message
	Message m(messageBody);
	onMessage(m);
	
	// Wait for a new message
	prepareForMessage();
}

void XmlConnection::sendMessage(const Message* m){
	messages_.push_back(m);

	// Send messages..
	if(!writing_){
		checkMessageQueue();
	}
}

void XmlConnection::checkMessageQueue(){
	if(messages_.empty()){
		return;
	}
	
	writing_ = true;

	ba::async_write(
		socket_, ba::buffer(messages_.front()->toString()), boost::bind(&XmlConnection::onWriteComplete, this, boost::asio::placeholders::error)
	);
}

void XmlConnection::onWriteComplete(const boost::system::error_code& error){
	messages_.pop_front();
	writing_ = false;

	if (error){
		onDisconnected();
		return;
	}
	
	checkMessageQueue();
}

}
